﻿#region License

// This file is part of Grawlix.
// 
// Grawlix is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// Grawlix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with Grawlix.  If not, see
// <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace Grawlix.Services.Resources
{
	/// <summary>
	/// A wrapper for <see cref="System.Drawing.Image" /> that can be
	/// serialized across <see cref="AppDomain" /> boundaries.
	/// </summary>
	[Serializable]
	public sealed class WrappedImage : ISerializable
	{
		/// <summary>
		/// The internally wrapped <see cref="System.Drawing.Image"/>.
		/// </summary>
		private readonly Image _imageData;

		/// <summary>
		/// Initializes the object, wrapping an existing image.
		/// </summary>
		/// <param name="image">The image to wrap.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="image"/> is null.
		/// </exception>
		public WrappedImage(Image image)
		{
			if (image == null)
				throw new ArgumentNullException("image");
			_imageData = image;
		}

		/// <summary>
		/// Initializes the object from serialization data.
		/// </summary>
		/// <param name="info">The source of this serialization.
		/// </param>
		/// <param name="context"> The <see cref="StreamingContext"/>
		/// which provides the serialization data.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="info"/> is null.
		/// </exception>
		/// <exception cref="SerializationException">
		/// Data from <paramref name="info"/> could not be used to
		/// reconstruct the image.
		/// </exception>
		[SecurityPermission(SecurityAction.LinkDemand,
			Flags = SecurityPermissionFlag.SerializationFormatter)]
		private WrappedImage(SerializationInfo info,
		                     StreamingContext context)
		{
			if (info == null)
				throw new ArgumentNullException("info");
			try
			{
				var data =
					(byte[])info.GetValue("ImageData", typeof(byte[]));
				_imageData = Image.FromStream(new MemoryStream(data));
				if (_imageData == null)
				{
					throw new SerializationException(
						"Attempt to deserialize an image failed due to " +
						"missing image data.");
				}
			}
			catch (InvalidCastException exception)
			{
				throw new SerializationException(
					"Unable to deserialize image data.", exception);
			}
		}

		/// <summary>
		/// The <see cref="System.Drawing.Image"/> wrapped by
		/// this <see cref="WrappedImage"/> object.
		/// </summary>
		public Image ImageData
		{
			get { return _imageData; }
		}

		/// <summary>
		/// Obtains serialization data from the current state of the object.
		/// </summary>
		/// <param name="info">The destination for this serialization.</param>
		/// <param name="context">
		/// The <see cref="StreamingContext"/> which stores
		/// the serialization data.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="info"/> is null.
		/// </exception>
		[SecurityPermission(SecurityAction.LinkDemand,
			Flags = SecurityPermissionFlag.SerializationFormatter)]
		void ISerializable.GetObjectData(SerializationInfo info,
		                                 StreamingContext context)
		{
			if (info == null)
				throw new ArgumentNullException("info");

			var stream = new MemoryStream();
			_imageData.Save(stream, _imageData.RawFormat);
			info.AddValue("ImageData", stream.ToArray(),
			              typeof(byte[]));
		}

		/// <summary>
		/// Obtains a string representation of this object.
		/// </summary>
		/// <returns>A string representation of this object.</returns>
		public override string ToString()
		{
			return _imageData.ToString();
		}
	}
}